﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LiteExpress.Utilities
{
    /// <summary>
    /// 请创建为static对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TaskDispatcher<T>
    {
        private List<Task> _workTasks;
        private CancellationTokenSource _tokenSource = new CancellationTokenSource();
        private BlockingCollection<T> _taskcollection;
        private Action<T> _func;
        private int _capability;


        public TaskDispatcher(int threadCount, Action<T> func, int capability = 500)
        {
            _capability = capability;
            _taskcollection = new BlockingCollection<T>(_capability);
            this._func = func;

            this._workTasks = Enumerable.Range(0, threadCount).Select(i => Task.Run((Action)this.StartWork)).ToList();
        }

        public void ResetTask()
        {
            #region reset token
            _tokenSource.Cancel();
            _tokenSource.Dispose();
            _tokenSource = new CancellationTokenSource();
            #endregion
            int taskcount = this._workTasks.Count;
            this._workTasks.ForEach(t =>
            {
                t.Dispose();
            });
            this._workTasks.Clear();

            this._workTasks = new List<Task>();
            this._workTasks = Enumerable.Range(0, taskcount).Select(i => Task.Run((Action)this.StartWork)).ToList();
        }

        public void Stop()
        {
            _tokenSource.Cancel();
        }

        public void AddWork(T parameters)
        {
            while (true)
            {
                if (_taskcollection.TryAdd(parameters))
                {
                    break;
                }
                else
                {
                    Thread.Sleep(100);
                    continue;
                }
            }
        }

        private void StartWork()
        {
            foreach (T parameter in _taskcollection.GetConsumingEnumerable())
            {
                if (_tokenSource.Token.IsCancellationRequested)
                {
                    break;
                }
                this._func(parameter);
            }
        }
    }
}
